#pragma once

#include <QObject>
#include <QSharedPointer>
#include <QString>

class PKGInfo;
/**
 * Data structure representing a Debian version.
 * @see deb-version(5)
 */
class PKGVersion
{
public:
    /** The epoch. It will be zero if no epoch is present. */
    unsigned int epoch;
    /** The upstream part of the version. */
    QString version;
    /** The Debian revision part of the version. */
    QString revision;
public:
    PKGVersion(int epoch = 0, const QString &version = QString(), const QString &revision = QString());
    PKGVersion(const QString &verstr);
    ~PKGVersion();
    void clear();
    bool operator>(const PKGVersion &dist);
    bool operator<(const PKGVersion &dist);
    bool operator==(const PKGVersion &dist);
    QString toString() const;
    const PKGVersion &fromString(const QString &verstr);
};

class PKGDepend
{
public:
    /**
     * @defgroup dpkg-db In-core package database management
     * @ingroup dpkg-public
     */
    enum class Type {
        dep_suggests = 0,
        dep_recommends,
        dep_depends,
        dep_predepends,
        dep_breaks,
        dep_conflicts,
        dep_provides,
        dep_replaces,
        dep_enhances,
        dep_recommended,
        dep_optional,
        dep_invalid = -1,
    };
    enum class VerCheck {
        dep_nocheck = 0,
        dep_equal,
        dep_great,
        dep_less,
        dep_great_or_equal,
        dep_less_or_equal
    };

public:
    QList<QSharedPointer<PKGDepend>> alternatives;
    QSharedPointer<PKGInfo> package;
    PKGDepend::Type type;
    PKGDepend::VerCheck vercheck;
public:
    PKGDepend(QSharedPointer<PKGInfo> package = nullptr, PKGDepend::Type type = PKGDepend::Type::dep_invalid);
    PKGDepend(const QString &str, const QString &type);
    ~PKGDepend();
    void clear();
    void extracted(QStringList &alts) const;
    QString toString() const;
    PKGDepend &fromString(const QString &str, const QString &type);

    QString ConvType(PKGDepend::Type value) const;
    PKGDepend::Type ConvType(const QString &value) const;

    QString ConvVerCheck(PKGDepend::VerCheck value) const;
    PKGDepend::VerCheck ConvVerCheck(const QString &value) const;
};

class PKGConfFile
{
public:
    QString name;
    QString hash;
    bool obsolete;
    bool remove_on_upgrade;
public:
    PKGConfFile(const QString &name = QString(), const QString &hash = QString(), bool obsolete = false, bool remove_on_upgrade = false);
};

class PKGArchiveDetails
{
public:
    QString name;
    QString msdosname;
    QString size;
    QString md5sum;
public:
    PKGArchiveDetails(const QString &name = QString(), const QString &msdosname = QString(), const QString &size = QString(), const QString &md5sum = QString());
    void field(const QString &member, const QString &value);
};

class PKGArch
{
public:
    enum class Type {
        DPKG_ARCH_NONE = 0,
        DPKG_ARCH_EMPTY,
        DPKG_ARCH_ILLEGAL,
        DPKG_ARCH_WILDCARD,
        DPKG_ARCH_ALL,
        DPKG_ARCH_NATIVE,
        DPKG_ARCH_FOREIGN,
        DPKG_ARCH_UNKNOWN,
    };
public:
    QString name;
    PKGArch::Type type;
public:
    PKGArch();
    PKGArch(QString name, PKGArch::Type type);
    PKGArch(const QString &archstr);
};

/**
 * Node describing a binary package file.
 * This structure holds information contained on each binary package.
 */
class PKGInfo
{
public:
    enum class MultiArch {
        PKG_MULTIARCH_NO = 0,
        PKG_MULTIARCH_SAME,
        PKG_MULTIARCH_ALLOWED,
        PKG_MULTIARCH_FOREIGN,
    };
    enum class Want {
        PKG_WANT_UNKNOWN = 0,
        PKG_WANT_INSTALL,
        PKG_WANT_HOLD,
        PKG_WANT_DEINSTALL,
        PKG_WANT_PURGE,
        /** Not allowed except as special sentinel value in some places. */
        PKG_WANT_SENTINEL,
    };
    enum class EFlag {
        PKG_EFLAG_OK = 0,
        PKG_EFLAG_REINSTREQ	= 1,
    };
    enum class Status {
        PKG_STAT_NOTINSTALLED = 0,
        PKG_STAT_CONFIGFILES,
        PKG_STAT_HALFINSTALLED,
        PKG_STAT_UNPACKED,
        PKG_STAT_HALFCONFIGURED,
        PKG_STAT_TRIGGERSAWAITED,
        PKG_STAT_TRIGGERSPENDING,
        PKG_STAT_INSTALLED,
    };
    enum class Priority {
        PKG_PRIO_REQUIRED = 0,
        PKG_PRIO_IMPORTANT,
        PKG_PRIO_STANDARD,
        PKG_PRIO_OPTIONAL,
        PKG_PRIO_EXTRA,
        PKG_PRIO_OTHER,
        PKG_PRIO_UNKNOWN,
        PKG_PRIO_UNSET = -1,
    };
public:
    QString name;
    QString pkgname_archqual;
    QString summary;
    QString description;
    QString maintainer;
    QString source;
    QString installedsize;
    QString origin;
    QString bugs;
    PKGInfo::Want want;
    PKGInfo::EFlag eflag;   /** The error flag bitmask. */
    PKGInfo::Status status;
    PKGInfo::Priority priority;
    PKGInfo::Priority package_class;
    PKGInfo::MultiArch multiarch;
    QString otherpriority;
    QString section;
    PKGVersion version;
    PKGVersion configversion;
    QList<PKGDepend> dep_replaces;
    QList<PKGDepend> dep_provides;
    QList<PKGDepend> dep_depends;
    QList<PKGDepend> dep_predepends;
    QList<PKGDepend> dep_recommends;
    QList<PKGDepend> dep_suggests;
    QList<PKGDepend> dep_breaks;
    QList<PKGDepend> dep_conflicts;
    QList<PKGDepend> dep_enhances;
    QList<PKGDepend> dep_recommended;
    QList<PKGDepend> dep_optional;
    bool essential;         /** The ‘essential’ flag, true = yes, false = no (absent). */
    bool is_protected;      /** The ‘protected’ flag, true = yes, false = no (absent). */
    PKGArch arch;
    QList<PKGConfFile> conffiles;
    QList<PKGArchiveDetails> archives;
public:
    bool isValid();
    QString depends() const;

    QString ConvWant(PKGInfo::Want value) const;
    PKGInfo::Want ConvWant(const QString &value) const;

    QString ConvEflag(PKGInfo::EFlag value) const;
    PKGInfo::EFlag ConvEflag(const QString &value) const;

    QString ConvStatus(PKGInfo::Status value) const;
    PKGInfo::Status ConvStatus(const QString &value) const;

    QString ConvPriority(PKGInfo::Priority value) const;
    PKGInfo::Priority ConvPriority(const QString &value) const;

    QString ConvMultiArch(PKGInfo::MultiArch value) const;
    PKGInfo::MultiArch ConvMultiArch(const QString &value) const;
};
